#ifndef MCL_DA_H_
#define MCL_DA_H_

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>

typedef intptr_t isize;
typedef uintptr_t usize;

// 定义名为 NAME 的动态数组（dynamic array）。
#define DEFINE_DA(NAME, TYPE) \
	struct NAME { \
		TYPE *data; \
		usize len; \
		usize cap; \
	}

// 动态数组的初始化列表。
#define DA_INIT {.data = NULL, .len = 0, .cap = 0}

// 清空动态数组（并不释放内存）。
#define DA_CLEAR(A) (A).len = 0

// 销毁动态数组，销毁后的动态数组会回到初始状态。
#define DA_DELETE(A) DA_DELETE_((A))
#define DA_DELETE_(A) \
	do { \
		if (A.data == NULL) \
			break; \
		free(A.data); \
		A.data = NULL; \
		A.len = 0; \
		A.cap = 0; \
	} while (false)

#define DA_INIT_CAP (2)

// 将 X 追加到动态数组的尾部。
#define DA_APPEND(A, X) DA_APPEND_((A), (X))
#define DA_APPEND_(A, X) \
	do { \
		if (A.len >= A.cap) { \
			A.cap = A.cap == 0 ? DA_INIT_CAP : A.cap * 2; \
			A.data = realloc(A.data, sizeof(*A.data) * A.cap); \
		} \
		A.data[A.len++] = X; \
	} while (false)

#define DA_POP(A) (A).len -= 1

// 保证动态数组中有保存 NEWCAP 个元素的内存。
#define DA_RESERVE(A, NEWCAP) DA_RESERVE_((A), (NEWCAP))
#define DA_RESERVE_(A, NEWCAP) \
	do { \
		usize newcap__ = NEWCAP; \
		while (newcap__ > A.cap) { \
			A.cap = A.cap == 0 ? DA_INIT_CAP : 2 * A.cap; \
		} \
		A.data = realloc(A.data, sizeof(*A.data) * A.cap); \
	} while (false)

// dstr 是 char 的动态数组，表示可以动态增长的字符串，它有自己的边界（len），不需要保证以 0 结尾。
DEFINE_DA(dstr, char);

// 仅可读的字符串视图，不拥有字符串所有权，不保证以 0 结尾。
struct dstr_view {
	char const *data;
	usize len;
};

#define DSTR_VIEW_INIT {.data = NULL, .len = 0}

// 从 dstr 获得字符串的视图。
static inline struct dstr_view dstr_get_view(struct dstr *dstr)
{
	return (struct dstr_view){.data = dstr->data, .len = dstr->len};
}

// 从 C 字符串获得 dstr_view。
static inline struct dstr_view dstr_view_from_cstr(char const *text)
{
	return (struct dstr_view){.data = text, .len = (usize)strlen(text)};
}

// 从 C 字符串（以 0 结尾）构造一个动态字符串。
struct dstr dstr_from_cstr(char const *text);

// 比较两个动态字符串是否相等。
bool dstr_eq(struct dstr *lhs, struct dstr *rhs);

// 比较两个动态字符是否跟 C 字符串相等。
bool dstr_eq_cstr(struct dstr *lhs, char const *rhs);

#endif
